package structs;

import java.util.LinkedList;

import interfaces.ICard;
import interfaces.IGame;
import interfaces.IPlayer;
import interfaces.Strategy;

public class Game implements IGame{

	private LinkedList<IPlayer> players;
	private int roundNumber = 1;
	private int turn = 0;
	private int aiPosition;
	private int teamPosition;
	private Deck deck;
	private ICard[] currentPlay;

	public Game(int numberPlayers, int aiPos) throws Exception{
		if(numberPlayers != 2 && numberPlayers != 4){
			throw new Exception("Wrong constructor");
		}
		
		this.aiPosition = aiPos;
		Strategy strat = null;
		this.deck = new Deck();
		this.players = new LinkedList<IPlayer>();
		this.currentPlay = new ICard[numberPlayers];

		if(numberPlayers == 2){
			strat = new SmarterStrategy(this);
		}
		else if(numberPlayers == 4){
			strat = new SmarterTeamStrategy(this);
			if(this.aiPosition + 2 <= 4){
				this.teamPosition = this.aiPosition + 2;
			}
			else {
				this.teamPosition = this.aiPosition - 2;
			}
		}
		
		for(int i = 0; i < numberPlayers; i++){		
			if(i == aiPos-1){
				this.players.add(new Player(i+1,this.deck, strat));
			}
			else{
				this.players.add(new Player(i+1,this.deck));
			}
		}
	}
	
	public Game(int numberPlayers, int aiPos, ICard removedCard) throws Exception{
		if(numberPlayers != 3){
			throw new Exception("Wrong constructor");
		}
		
		this.aiPosition = aiPos;
		Strategy strat = null;
		this.players = new LinkedList<IPlayer>();
		this.currentPlay = new ICard[numberPlayers];

		this.deck = new Deck(removedCard);
		
		for(int i = 0; i < numberPlayers; i++){		
			if(i == aiPos-1){
				this.players.add(new Player(i+1,this.deck, strat));
			}
			else{
				this.players.add(new Player(i+1,this.deck));
			}
		}	
	}

	public String start() {
		String message = "";
		
		String trySw = this.players.get(this.aiPosition-1).trySwapLife();
		
		if(!trySw.isEmpty()){
			message += trySw;
		}
		
		return message;
	}

	public boolean nextHasMove() {
		if(this.turn == aiPosition-1){
			return true;
		}
		
		return false;
	}
	
	public boolean next(){
		if(this.turn + 1 == players.size()){
			this.turn = 0;
			this.roundNumber++;
			
			return false;
		}
		
		this.turn++;	
		return true;
	}
	
	public String roundOver(){
		//Test who won and put cards to winners winStack
		ICard max = this.currentPlay[0];
		int maxPos = 0;
		String playSuit = this.currentPlay[0].getSuit();
				
		for(int i = 1 ; i < this.players.size(); i++){
			if(	
				//Max no es vida y currentPlay es vida
				(!max.getSuit().equalsIgnoreCase(this.deck.getLife().getSuit()) 
						&& this.currentPlay[i].getSuit().equalsIgnoreCase(this.deck.getLife().getSuit())) ||
				//Max es vida, currentPlay es vida, currentPlay tiene mas puntos
				(max.getSuit().equalsIgnoreCase(this.deck.getLife().getSuit()) 
						&& this.currentPlay[i].getSuit().equalsIgnoreCase(this.deck.getLife().getSuit()) 
						&& max.getPoints() < this.currentPlay[i].getPoints()) ||
				//Max es vida, currentPlay es vida, currentPlay vale 0 pntos, max vale 0 pnts, currentPlay tiene un numero mas grande q max
				(max.getSuit().equalsIgnoreCase(this.deck.getLife().getSuit()) 
						&& this.currentPlay[i].getSuit().equalsIgnoreCase(this.deck.getLife().getSuit()) 
						&& this.currentPlay[i].getPoints() == 0 
						&& max.getPoints() == 0 
						&& this.currentPlay[i].getNumber() > max.getNumber()) ||
				//CurrentPlay es del Playsuit, max es del playSuit, currentPlay tiene mas puntos que max
				(this.currentPlay[i].getSuit().equalsIgnoreCase(playSuit) 
						&& max.getSuit().equalsIgnoreCase(playSuit)
						&& max.getPoints() < this.currentPlay[i].getPoints()) ||
				//currentPlay es del playSuit, max es del playSuit, ambos tienes 0 pnts, currentPlay tiene un numero mas grande q max
				(this.currentPlay[i].getSuit().equalsIgnoreCase(playSuit) 
						&& max.getSuit().equalsIgnoreCase(playSuit)
						&& this.currentPlay[i].getPoints() == 0 
						&& max.getPoints() == 0 
						&& this.currentPlay[i].getNumber() > max.getNumber())
			){
				max = this.currentPlay[i];
				maxPos = i;
			}
			
		}
		
		//Clear for next round and add to winStack
		for(int i = 0 ; i < this.players.size(); i++){
			this.players.get(maxPos).addToWinStack(this.currentPlay[i]);
			this.currentPlay[i] = null;
		}
		
		String winner = this.players.get(maxPos).getName();
		
		IPlayer ai = this.players.get(this.aiPosition-1);
		LinkedList<IPlayer> reorder = new LinkedList<IPlayer>();
		
		for(int i = maxPos ; i < this.players.size(); i++){
			if(this.players.get(i) == ai){
				this.aiPosition = reorder.size() + 1;
			}
			reorder.add(this.players.get(i));
		}
		for(int i = 0 ; i < maxPos; i++){
			if(this.players.get(i) == ai){
				this.aiPosition = reorder.size() + 1;
			}
			reorder.add(this.players.get(i));
		}

		//Get new teamPosition
		if(this.players.size() == 4){
			if(this.aiPosition + 2 <= 4){
				this.teamPosition = this.aiPosition + 2;
			}
			else {
				this.teamPosition = this.aiPosition - 2;
			}
		}
		
		this.players = reorder;
		
		return winner;
	}
	
	public int getRoundNumber() {
		return this.roundNumber;
	}

	public boolean hasEnded(){
		if(this.players.size() * this.roundNumber > this.deck.getSize()){
			return true;
		}
		
		return false;
	}
	
	public LinkedList<IPlayer> getPlayers(){
		return this.players;
	}
	
	public IPlayer getCurrentPlayer() {
		return this.players.get(this.turn);
	}

	public IPlayer getAIPlayer(){
		return this.players.get(this.aiPosition-1);
	}
	 	
	public int getAIPosition(){
		return this.aiPosition;
	}
	
	public IPlayer getTeamPlayer(){
		return this.players.get(this.teamPosition-1);
	}
	 	
	public int getTeamPosition(){
		return this.teamPosition;
	}

	public Deck getDeck(){
		return this.deck;
	}
	
	public int getCurrentHandTurn()
	{
		return this.turn;
	}

	public void addCurrentPlay(ICard card){
		this.currentPlay[this.turn] = card;
	}
	
	public int getTeamWinStackPoints()
	{
		return this.getTeamPlayer().getWinStackPoints() + this.getAIPlayer().getWinStackPoints();
	}
	
	public int getOpponentsWinStackPoints()
	{
		if(this.aiPosition == 1 || this.aiPosition==3)
		{
		return (this.getPlayers().get(1).getWinStackPoints() + this.getPlayers().get(3).getWinStackPoints());
		}
		else{
			return (this.getPlayers().get(0).getWinStackPoints() + this.getPlayers().get(2).getWinStackPoints());
		}
	}
	
	public ICard[] getCurrentCardsPlayed()
	{
		return this.currentPlay;
	}
}
